home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 49
/
Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso
/
-serious-
/
misc
/
db3.6-beta
/
db3.6-beta-src
/
dbgui.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-11-30
|
48KB
|
1,113 lines
/*
* GUI Designed by : David Ekholm, Datadosen
*/
#include <stdlib.h> /* atoi() */
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h> /* DrawInfo */
#include <intuition/classes.h>
#include <intuition/classusr.h>
#include <intuition/imageclass.h>
#include <intuition/gadgetclass.h>
#include <gadgets/textfield.h>
#include <intuition/sghooks.h> /* struct SGWork here */
#include <workbench/workbench.h> /* For AppWindow */
#include <libraries/gadtools.h>
#include <libraries/commodities.h> /* This has a nice qualifier #define */
#include <libraries/iffparse.h>
#include <graphics/displayinfo.h>
#include <graphics/gfxbase.h>
#include <graphics/text.h> /* For my TextAttr struct */
#include <graphics/rastport.h>
#include <utility/hooks.h> /* For my stringhook */
#include <proto/wb.h> /* For AppWindow */
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/graphics_protos.h>
#include <clib/utility_protos.h>
#include <string.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/intuition_pragmas.h>
#include <pragmas/gadtools_pragmas.h>
#include <pragmas/graphics_pragmas.h>
#include <pragmas/utility_pragmas.h>
#include <proto/textfield.h>
#include "dbGUI.h"
#include "db.h"
#include "dbparser.h"
#include "Version.h"
#define TOGGLE_LED *(UBYTE *)0xbfe001 ^= 2
extern Class *TextFieldClass;
extern struct IFFHandle *Iff0;
struct Screen *Scr = NULL;
struct DrawInfo *DrInfo = NULL;
UWORD *Pens;
APTR VisualInfo = NULL;
struct IntuiMessage DB_Msg;
UWORD DB_Zoom[4];
struct Gadget *LastGad = NULL;
struct Hook MyStrHook;
struct TextAttr *Font, Attr;
UWORD FontX, FontY;
UWORD OffX, OffY;
UWORD DragKnobWidth, DragKnobHeight;
WORD LastLeftEdge=-1;
WORD LastTopEdge=-1; /* For nice layoutswitching */
/*For gadgetlayout */
UWORD TabSize;
/* For MyStrHookFunc() */
BOOL ReactivateGad = FALSE;
BOOL GadDoubleClicked = FALSE;
struct Gadget *NextGad = NULL;
struct TextAttr UserTextAttr =
{
NULL, 0, FS_NORMAL, FPF_DISKFONT
};
struct NewMenu DB_NewMenu[] = {
NM_TITLE, (STRPTR)MSG_PROJECT_MENU , NULL, 0, NULL, NULL,
NM_ITEM, (STRPTR)MSG_PROJECT_NEW , NULL, 0, 0L, (APTR)DB_NEW,
NM_ITEM, (STRPTR)MSG_PROJECT_OPEN , NULL, 0, 0L, (APTR)DB_OPEN,
NM_ITEM, (STRPTR)MSG_PROJECT_RELOAD, NULL, 0, 0L, (APTR)DB_RELOAD,
NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
NM_ITEM, (STRPTR)MSG_PROJECT_SAVE , NULL, 0, 0L, (APTR)DB_SAVE,
NM_ITEM, (STRPTR)MSG_PROJECT_SAVE_AS, NULL, 0, 0L, (APTR)DB_SAVEAS,
NM_ITEM, (STRPTR)MSG_PROJECT_OUTPUT , NULL, 0, NULL,NULL,
NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_VIEW, NULL, 0, 0L, (APTR)DB_OUTPUT_VIEW,
NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_VIEW_WN, NULL, 0, 0L, (APTR)DB_OUTPUT_VIEW_WN,
NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_TAB_ASCII, NULL, 0, 0L, (APTR)DB_OUTPUT_TAB_ASCII,
NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_COMMA_ASCII, NULL, 0, 0L, (APTR)DB_OUTPUT_COMMA_ASCII,
NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
NM_ITEM, (STRPTR)MSG_PROJECT_ABOUT, NULL, 0, 0L, (APTR)DB_ABOUT,
NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
NM_ITEM, (STRPTR)MSG_PROJECT_QUIT, NULL, 0, 0L, (APTR)DB_QUIT,
NM_TITLE, (STRPTR)MSG_EDIT_MENU, NULL, 0, NULL, NULL,
NM_ITEM, (STRPTR)MSG_EDIT_CUT, NULL, 0, 0L, (APTR)DB_CUT,
NM_ITEM, (STRPTR)MSG_EDIT_COPY, NULL, 0, 0L, (APTR)DB_COPY,
NM_ITEM, (STRPTR)MSG_EDIT_PASTE, NULL, 0, 0L, (APTR)DB_PASTE,
NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
NM_ITEM, (STRPTR)MSG_EDIT_ADD, NULL, 0, 0L, (APTR)DB_ADD,
NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
NM_ITEM, (STRPTR)MSG_EDIT_KILL, NULL, 0, 0L, (APTR)DB_KILL,
NM_TITLE, (STRPTR)MSG_VIEW_MENU, NULL, 0, NULL, NULL,
NM_TITLE, (STRPTR)MSG_ACTION_MENU, NULL, 0, NULL, NULL,
NM_ITEM, (STRPTR)MSG_ACTION_FIND, NULL, 0, 0L, (APTR)DB_FIND,
NM_ITEM, (STRPTR)MSG_ACTION_FIND_NEXT, NULL, 0, 0L, (APTR)DB_FINDNEXT,
NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
NM_ITEM, (STRPTR)MSG_ACTION_SORT, NULL, 0, 0L, (APTR)DB_SORT,
NM_ITEM, (STRPTR)MSG_ACTION_DIAL, NULL, 0, 0L, (APTR)DB_DIAL,
NM_ITEM, (STRPTR)MSG_ACTION_BROWSE, NULL, 0, 0L, (APTR)DB_BROWSE,
NM_TITLE, (STRPTR)MSG_SETTINGS_MENU, NULL, 0, NULL, NULL,
NM_ITEM, (STRPTR)MSG_SETTINGS_WARNINGS, NULL, CHECKIT|CHECKED|MENUTOGGLE, 0L, (APTR)DB_WARNINGS,
NM_ITEM, (STRPTR)MSG_SETTINGS_SORTDIR, NULL, 0, NULL, NULL,
NM_SUB, (STRPTR)MSG_SETTINGS_SORTDIR_AZ, NULL, CHECKIT|CHECKED, 2L, (APTR)DB_AZ,
NM_SUB, (STRPTR)MSG_SETTINGS_SORTDIR_ZA, NULL, CHECKIT, 1L, (APTR)DB_ZA,
NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
NM_ITEM, (STRPTR)MSG_SETTINGS_FIELD_DEFINITION, NULL, NM_ITEMDISABLED, 0L, (APTR)DB_FIELD_DEFINITION,
NM_ITEM, (STRPTR)MSG_SETTINGS_VIEW_DESIGN, NULL, 0L, 0L, (APTR)DB_VIEW_DESIGN,
NM_TITLE, (STRPTR)MSG_AREXX_MENU, NULL, 0, NULL, NULL,
NM_ITEM, (STRPTR)MSG_AREXX_EXECUTE, NULL, 0, 0L, (APTR)DB_EXECUTE_AREXX,
NM_ITEM, (STRPTR)MSG_AREXX_EXECUTE_RELAUNCH, NULL, 0, 0L, (APTR)DB_EXECUTE_AREXX_AGAIN,
NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
NM_END, NULL, NULL, 0, 0L, NULL };
void LocalizeMenu(struct NewMenu *nm)
{
/* Replaces the string-indexes in the NewMenu array with localized text */
/* Gets called once from SetupScreen() */
UWORD i=0;
while (nm[i].nm_Type != NM_END) {
if (nm[i].nm_Label != NM_BARLABEL) {
nm[i].nm_CommKey = GetAppStr((LONG)nm[i].nm_Label);
nm[i].nm_Label = nm[i].nm_CommKey+2;
if (nm[i].nm_CommKey[0] == ' ') nm[i].nm_CommKey = NULL;
}
++i;
}
}
/**/
__inline BOOL OkStrGad(struct Gadget *g)
{
return (BOOL)(g->Flags & GFLG_TABCYCLE && !(g->Flags & GFLG_DISABLED));
}
struct Gadget *PrevStrGad(struct Gadget *Gad, struct Gadget *glist)
{
/* Returns the previous stringgadget, or NULL if Gad is the first one */
struct Gadget *strgad = NULL, *g = glist;
if (g == Gad) return NULL;
for (; g; g = g->NextGadget) {
if (OkStrGad(g)) strgad = g; /* Only return stringgads */
if (g->NextGadget == Gad) break;
}
return strgad;
}
struct Gadget *EndGad(struct Gadget *g)
{
while (g->NextGadget) g = g->NextGadget;
return g;
}
struct Gadget *ActivateThisGad(ULONG actions, struct Gadget *current,
struct Gadget *glist)
{
/* Takes over the job of deciding which (if any) gadget should be reactivated
* based upon the SGWork->Actionfield.
* Without this function, it is impossible to activate other stringgadgets
* (as responce to an ARexx command) as Intiuition otherwize will have
* activated some other gadget first if the user cyclesteps thru a gadgetlist.
*/
struct Gadget *g = NULL;
if (actions & SGA_NEXTACTIVE) {
for (g = current->NextGadget;; g = g->NextGadget) {
if (!g) g = glist;
if (OkStrGad(g)) break;
}
}
else if (actions & SGA_PREVACTIVE) {
for (g = PrevStrGad(current, glist);; g = PrevStrGad(g, glist)) {
if (!g) g = EndGad(glist);
if (OkStrGad(g)) break;
}
}
return g;
}
/* Stuff for my stringHook */
ULONG __saveds __asm MyStrHookFunc(register __a0 struct Hook *hook,
register __a2 struct SGWork *sgw,
register __a1 ULONG *msg)
{
/* This hook does the following modifications to a gadtool stringgadet:
* Pressing ESC will terminate the gadget without leaving the ESC char.
* Pressing R-Amiga+Key will terminate the gadget leaving the keycode in
* the Code field of the GadgetUp IDCMP event that will follow. It will
* also reuse the inputevent, making Intition select the corresponding menu.
* Pressing up, down, shift-up or shift-down will navigate between records.
* It also responds to the keys F1 to F10.
* Doubleclicking into a stringgadget will invoke a special function
*/
static ULONG StartSecs=0, StartMicros=0;
ULONG CurrentSecs, CurrentMicros;
ULONG return_code = ~0;
if (*msg == SGH_KEY) { /* Process some key event */
if ((sgw->EditOp == EO_REPLACECHAR) || (sgw->EditOp == EO_INSERTCHAR)) {
/* sgw->Code is VANILLAKEY, sgw->IEvent->ie_Code is RAWKEY */
if (sgw->IEvent->ie_Code == RAW_ESC) { /* ESC pressed */
sgw->Actions &= ~SGA_USE; /* ~SGA_BEEP will not prevent beep :-( */
sgw->Actions |= SGA_END; /* NewEdit does this */
}
else if (sgw->IEvent->ie_Qualifier &
(IEQUALIFIER_RCOMMAND | IEQUALIFIER_LCOMMAND)) {
sgw->Actions &= ~SGA_USE;
sgw->Actions |= SGA_END | SGA_REUSE;
/**/ ReactivateGad = TRUE;
}
}
else if (sgw->EditOp == EO_ENTER && sgw->Code != RAW_HELP) {
if (!(MyArgArray[NORETURNSTEP] ||
sgw->IEvent->ie_Qualifier & IXSYM_ALTMASK)) {
if (sgw->IEvent->ie_Qualifier & IXSYM_SHIFTMASK)
sgw->Actions |= SGA_PREVACTIVE;
else sgw->Actions |= SGA_NEXTACTIVE;
}
}
else if (sgw->EditOp == EO_NOOP) {
if (sgw->IEvent->ie_Code == RAW_DOWN || sgw->IEvent->ie_Code == RAW_UP) {
/* Down or up key pressed */
sgw->Actions &= ~SGA_USE;
sgw->Actions |= SGA_END | SGA_REUSE;
ReactivateGad = TRUE;
}
else if (sgw->IEvent->ie_Code == RAW_ESC) { /* ESC pressed */
sgw->Actions &= ~SGA_USE; /* ~SGA_BEEP will not prevent beep :-( */
sgw->Actions |= SGA_END; /* NewEdit does this */
}
else if (sgw->IEvent->ie_Code >= RAW_F1 && sgw->IEvent->ie_Code <= RAW_F10) {
sgw->Actions &= ~SGA_USE;
sgw->Actions |= SGA_END | SGA_REUSE;
}
}
if (sgw->Actions & SGA_END) {
if (NextGad = ActivateThisGad(sgw->Actions, sgw->Gadget,
sgw->GadgetInfo->gi_Window->FirstGadget))
sgw->Actions &= ~(SGA_PREVACTIVE | SGA_NEXTACTIVE);
}
}
else if (*msg == SGH_CLICK) { /* Process mouse click */
CurrentSecs = sgw->IEvent->ie_TimeStamp.tv_secs;
CurrentMicros = sgw->IEvent->ie_TimeStamp.tv_micro;
if (DoubleClick(StartSecs, StartMicros, CurrentSecs, CurrentMicros)
&& sgw->BufferPos == sgw->StringInfo->BufferPos) {
/* Only allow doubleclick if user doubleclicks at the same character */
/* to avoid accidental doubleclick if user only wants to position */
/* cursor exactly */
GadDoubleClicked = TRUE;
StartSecs = StartMicros = 0; /* Prevent "triple clicks" */
}
else {
StartSecs = CurrentSecs;
StartMicros = CurrentMicros;
}
}
else return_code = 0;
return return_code;
}
void InitHook(struct Hook *hook)
{
hook->h_Entry = (HOOKFUNC)MyStrHookFunc;
hook->h_SubEntry = NULL;
hook->h_Data = 0;
}
int SetupScreen( void )
{
/*
struct Screen *s;
if (!Stricmp(MyArgArray[PUBSCREEN] "frontmost")) {
for (s = IntuitionBase->FirstScreen; s; s = s->NextScreen)
if (s->Flags & PUBLICSCREEN)
}
else {
*/
if (!(Scr = LockPubScreen((STRPTR)MyArgArray[PUBSCREEN])))
if (!(Scr = LockPubScreen(NULL))) /* Workbench */
return( 1L );
/* } */
if ( ! ( VisualInfo = GetVisualInfo( Scr, TAG_DONE )))
return( 2L );
if ( ! (DrInfo = GetScreenDrawInfo(Scr)))
return 3L;
Pens = DrInfo->dri_Pens;
LocalizeMenu(DB_NewMenu);
LocalizeMenu(DesignNewMenu);
InitHook(&MyStrHook);
return( 0L );
}
void CloseDownScreen( void )
{
if (DrInfo) FreeScreenDrawInfo(Scr, DrInfo);
if ( VisualInfo ) {
FreeVisualInfo( VisualInfo );
VisualInfo = NULL;
}
if ( Scr ) {
UnlockPubScreen( NULL, Scr );
Scr = NULL;
}
}
int HandleDB_IDCMP(struct Layout *Lay)
{
struct IntuiMessage *m;
struct MenuItem *n;
int (*func)(void);
struct Window *Win = Lay->Window;
struct VisFldInfo *vf;
BOOL running = TRUE;
while( m = GT_GetIMsg( Win->UserPort )) {
CopyMem(( char * )m, ( char * )&DB_Msg, (long)sizeof( struct IntuiMessage ));
GT_ReplyIMsg( m );
switch ( DB_Msg.Class ) {
case IDCMP_INTUITICKS:
if (GadDoubleClicked) {
running = DB_SpecialAction(TRUE);
GadDoubleClicked = FALSE;
}
break;
case IDCMP_REFRESHWINDOW:
GT_BeginRefresh(Win);
GT_EndRefresh(Win, TRUE );
break;
case IDCMP_CLOSEWINDOW:
running = DB_CloseWindow();
break;
case IDCMP_MENUHELP:
running = DB_MenuHelp();
break;
case IDCMP_NEWSIZE:
running = DB_NewSize();
break;
case IDCMP_VANILLAKEY:
if (!(NextGad && (NextGad->Flags & GFLG_SELECTED)))
running = DB_VanillaKey();
break;
case IDCMP_RAWKEY:
if (!(NextGad && (NextGad->Flags & GFLG_SELECTED)))
running = DB_RawKey();
if (running) return running; /* The window has been closed! */
break;
case IDCMP_GADGETUP:
{
struct Gadget *gad = (struct Gadget *)DB_Msg.IAddress;
if (gad->GadgetID == SCROLLER_KIND) DragGadgetSelected();
else {
if ((gad->GadgetID == CHECKBOX_KIND) ||
(gad->GadgetID == CYCLE_KIND)) {
LastGad = gad;
VisFldSelected(gad);
vf = GetVisFldInfo(Lay, gad);
vf->Code = DB_Msg.Code;
}
if (!ReactivateGad)
running = DB_SpecialAction(FALSE);
if (NextGad) ActivateGadget(NextGad, Win, NULL);
}
}
break;
case IDCMP_GADGETDOWN:
{
struct Gadget *gad = (struct Gadget *)DB_Msg.IAddress;
if (gad->GadgetID == STRING_KIND || gad->GadgetID == TEXTFIELD_KIND) {
LastGad = gad;
VisFldSelected(gad);
}
else if (gad->GadgetID == SCROLLER_KIND) DragGadgetSelected();
}
break;
case IDCMP_MENUPICK:
while( DB_Msg.Code != MENUNULL ) {
n = ItemAddress( Win->MenuStrip, DB_Msg.Code );
func = (int (*)(void))(GTMENUITEM_USERDATA( n ));
running = func();
if (running) return running; /* The window has been closed! */
DB_Msg.Code = n->NextSelect;
}
break;
/* Added by me as GadToolBox won't do that */
case IDCMP_MOUSEMOVE:
DB_MouseMove();
break;
}
}
if (ReactivateGad) ReactivateGad = FALSE;
return( running );
}
void DeleteSoftMenu(struct SoftMenu *sm)
{
if (sm->Items) FreeMenus((struct Menu *)sm->Items);
sm->Items = NULL;
if (sm->NewItems) FreeMem(sm->NewItems, sm->NewItemsNum * sizeof(struct NewMenu));
sm->NewItems = NULL;
sm->NewItemsNum = 0;
}
void CloseMenu(struct Pro *Pr)
{
/* Frees all memory allocated by OpenMenu() */
if (Pr->Menu) FreeMenus(Pr->Menu);
Pr->Menu = NULL;
DeleteSoftMenu(&Pr->ViewMenu);
DeleteSoftMenu(&Pr->ARexxMenu);
}
int AddViewMenu(struct Pro *Pr)
{
int n;
struct Layout *Lay;
/* Count how many layouts there are */
for (n=0, Lay=Pr->FirstLayout; Lay; Lay=Lay->NextLayout, n++);
if (!n) return 0; /* No layouts at all. Extra safety */
Pr->ViewMenu.NewItemsNum = n+1; /* One extra array-closing item */
/* Allocate memory for the NewMenu structs */
if (!(Pr->ViewMenu.NewItems =
AllocMem(Pr->ViewMenu.NewItemsNum * sizeof(struct NewMenu), MEMF_CLEAR))) return MEM_ERR;
/* Fill in the NewMenu structs */
for (n=0, Lay=Pr->FirstLayout; Lay; Lay=Lay->NextLayout, n++) {
Pr->ViewMenu.NewItems[n].nm_Type = NM_ITEM;
Pr->ViewMenu.NewItems[n].nm_Label = (STRPTR)Lay->Name;
Pr->ViewMenu.NewItems[n].nm_Flags = CHECKIT;
Pr->ViewMenu.NewItems[n].nm_MutualExclude = ~(1<<n);
Pr->ViewMenu.NewItems[n].nm_UserData = (APTR)DB_VIEW;
}
Pr->ViewMenu.NewItems[n].nm_Type = NM_END;
Pr->ViewMenu.NewItems[0].nm_Flags |= CHECKED;
if (!(Pr->ViewMenu.Items = (struct MenuItem *)CreateMenus(Pr->ViewMenu.NewItems, TAG_DONE))) return MENU_ERR;
Pr->Menu->NextMenu->NextMenu->FirstItem = Pr->ViewMenu.Items; /* Link in */
return 0; /* ok */
}
int AddARexxMenu(struct Pro *Pr)
{
int n;
struct RxInfo *ri;
struct RFFTag *tag;
char *label;
/* Count how many ARexx items there are */
for (n=0, ri=Pr->FirstRxInfo; ri; ri=ri->Next, n++);
if (n < 2) return 0; /* No ARexx menu items at all (The global RFF data is in the first node). */
Pr->ARexxMenu.NewItemsNum = n; /* One extra array-closing item */
/* Allocate memory for the NewMenu structs */
if (!(Pr->ARexxMenu.NewItems =
AllocMem(Pr->ARexxMenu.NewItemsNum * sizeof(struct NewMenu), MEMF_CLEAR))) return MEM_ERR;
/* Fill in the NewMenu structs */
for (n=0, ri=Pr->FirstRxInfo->Next; ri; ri=ri->Next, n++) {
Pr->ARexxMenu.NewItems[n].nm_Type = NM_ITEM;
if (!(tag = FindTag(&ri->RxTags, NAME)) && !(tag = FindTag(&ri->RxTags, RXFILE)))
label = "« error »";
else label = tag->Data;
Pr->ARexxMenu.NewItems[n].nm_Label = (STRPTR)label;
Pr->ARexxMenu.NewItems[n].nm_UserData = (APTR)DB_AREXX;
}
Pr->ARexxMenu.NewItems[n].nm_Type = NM_END;
if (!(Pr->ARexxMenu.Items = (struct MenuItem *)CreateMenus(Pr->ARexxMenu.NewItems, TAG_DONE))) return MENU_ERR;
Pr->Menu->NextMenu->NextMenu->NextMenu->NextMenu->NextMenu->
FirstItem->NextItem->NextItem->NextItem = Pr->ARexxMenu.Items; /* Link in */
return 0; /* ok */
}
int OpenMenu(struct Pro *Pr)
{
/* Builds a complete menu including the variable View menu */
int err;
if (!(Pr->Menu = CreateMenus(DB_NewMenu, TAG_DONE))) return MENU_ERR;
if (err = AddViewMenu(Pr)) {
CloseMenu(Pr);
return err;
}
if (err = AddARexxMenu(Pr)) {
CloseMenu(Pr);
return err;
}
LayoutMenus(Pr->Menu, VisualInfo, GTMN_NewLookMenus, TRUE, TAG_DONE );
return 0;
}
void GadSpace(struct VisFldInfo *vf, struct RastPort *rp)
{
/* Calculate the offset and size of a vf info vf->Pos. */
/* Take space for the gadgets name into account */
/* If rp is NULL then topaz 8 is assumed */
int len;
char *buffer, *bufp, *namep;
int diff, rows;
struct RFFTag *tag;
vf->Pos.YOffset = vf->Pos.XOffset = 0;
vf->Label.LeftEdge = vf->Label.TopEdge = 0; /* textfield gadget */
tag = SearchTag(CurrentPro, vf, NULL, PLACE);
if (tag && !Stricmp(tag->Data, "above")) { /* Title is above gadget */
vf->Pos.YOffset = FontY + (FontY >> 1); /* Seems to look nice */
vf->Label.TopEdge = -vf->Pos.YOffset; /* textfield gadget */
}
else { /* Title is to the left of gadget */
/* gadgetname size */
len = strlen(vf->Name);
if (!(buffer = AllocMem(len+1,0))) return; /* mem fail */
/* Strip underscore _ in gadetname for correct length */
for (bufp = buffer, namep = vf->Name;; namep++) {
if (*namep != '_') *bufp++ = *namep;
if (!(*namep)) break; /* Also copy the \0 char */
}
if (rp) vf->Pos.XOffset = TextLength(rp,buffer,strlen(buffer));
else vf->Pos.XOffset = FontX * strlen(buffer); /* Topaz 8 */
FreeMem(buffer, len+1);
if (vf->Pos.XOffset) vf->Pos.XOffset += FontX; /* If vf->name, add extra space */
vf->Label.LeftEdge = -vf->Pos.XOffset; /* textfield gadget */
}
vf->Pos.Width = FontX * (vf->VisLen + 2);
diff = vf->Pos.XOffset % FontX;
if (diff) vf->Pos.XOffset += FontX - diff; /* Snap to next FontX tick */
tag = SearchTag(CurrentPro, vf, NULL, ROWS);
if (tag && (rows = atoi(tag->Data))) {
vf->Pos.Height = FontY * rows + STRGADFRAMESHEIGHT;
}
else vf->Pos.Height = FontY + STRGADFRAMESHEIGHT;
}
__inline WORD LineOffset(struct VisFldInfo *vf)
{
/* Return the maximum Y offset needed for a line of visual fields */
WORD oldmax = 0;
for (; vf; vf = vf->Next) {
if (vf->Pos.YOffset > oldmax) oldmax = vf->Pos.YOffset;
if (vf->VisSep == '\n' || vf->VisSep == '\f') break;
}
return oldmax;
}
__inline BOOL EndOfLine(struct VisFldInfo *vf)
{
return (BOOL)(vf->VisSep == '\n' || vf->VisSep == '\f' || !vf->Next);
}
BOOL CalcPos(struct Layout *Lay, struct Space *GLim, WORD *ww, WORD *wh,
struct RastPort *rp)
{
struct VisFldInfo *vf;
WORD curX = 0, curY = 0;
BOOL firstCol = TRUE;
int stepsize = 0;
WORD maxheight = 0;
GLim->XOffset = GLim->Width = GLim->YOffset = GLim->Height = 0;
/* First set each vf's local offset and size */
for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next)
GadSpace(vf, rp);
/* Now adjust all vf's according to one another */
for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {
if (firstCol) {
curY += LineOffset(vf); /* This line's max Y offset */
if (vf->Pos.XOffset > GLim->XOffset) GLim->XOffset = vf->Pos.XOffset;
vf->Pos.XOffset = 0; /* It will be added later */
}
vf->Pos.XOffset += curX;
vf->Pos.YOffset = curY;
if (stepsize) {
vf->Pos.XOffset += stepsize - vf->Pos.XOffset % stepsize;
stepsize = 0;
}
if (vf->Pos.XOffset + vf->Pos.Width > GLim->Width)
GLim->Width = vf->Pos.XOffset + vf->Pos.Width;
if (vf->Pos.Height > maxheight) maxheight = vf->Pos.Height;
if (EndOfLine(vf)) {
firstCol = TRUE;
curX = 0;
curY += maxheight;
GLim->Height = curY;
maxheight = 0;
}
switch (vf->VisSep) {
case ' ':
curX = vf->Pos.XOffset + vf->Pos.Width + FontX;
firstCol = FALSE;
stepsize = 0;
break;
case '\t':
curX = vf->Pos.XOffset + vf->Pos.Width + FontX;
stepsize = TabSize * FontX;
firstCol = FALSE;
break;
case '\f':
curY += (FontY * 3 >> 1); /* Looks nice */
break;
case '\n':
default:
curY += (FontY * 3 >> 3); /* Looks nice */
break;
}
}
GLim->Width += GLim->XOffset;
*ww = OffX + (FontX << 1) + GLim->Width + Scr->WBorRight;
*wh = OffY + FontY + GLim->Height + Scr->WBorBottom;
if (MyArgArray[HORIZBAR]) *wh += DragKnobHeight;
else *ww += DragKnobWidth;
return TRUE;
}
void DeleteAllGadgets(struct Layout *Lay, char mode)
{
struct VisFldInfo *vf;
struct Gadget *g;
/* Relink the gadgetborders we deleted for sake of speed */
if (mode == USE_MODE && Lay->FirstSR) SpeedRenderOff(Lay); /* FirstSR will be cleared */
if (Lay->GList) {
if (mode == USE_MODE && Lay->Window) RemoveGList(Lay->Window, Lay->GList, -1);
/* Remove objects first */
for (g = Lay->GList; g && g->NextGadget; g = g->NextGadget) {
if (g->NextGadget->GadgetID == TEXTFIELD_KIND) {
DisposeObject(g->NextGadget);
g->NextGadget = g->NextGadget->NextGadget; /* Objects shall not be freed by FreeGadgets */
}
}
FreeGadgets(Lay->GList);
Lay->GList = NULL;
}
for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {
vf->Gadget = NULL;
vf->Code = 0;
}
LastGad = NULL;
}
void CloseLayWin(struct Pro *Pr, struct Layout *Lay)
{
CloseSelect(CurrentPro->CurrentLayout->Browser);
RemoveAllStrings(CurrentPro->CurrentLayout->Browser);
DeleteAllGadgets(Lay, USE_MODE);
if (Lay->Window) {
/* Remember old window pos */
LastLeftEdge = Lay->Window->LeftEdge;
LastTopEdge = Lay->Window->TopEdge;
/* AppWindow specifics */
if (Lay->AppWin) RemoveAppWindow(Lay->AppWin);
Lay->AppWin = NULL;
ClearMenuStrip(Lay->Window);
CloseWindow(Lay->Window);
Lay->Window = NULL;
}
}
void AdjustVars(struct RastPort *rp)
{
/* Supportfunction to simplify OpenLayWin */
if (rp) {
Font->ta_Name = (STRPTR)rp->Font->tf_Message.mn_Node.ln_Name;
Font->ta_YSize = FontY = rp->Font->tf_YSize;
FontX = rp->Font->tf_XSize;
}
else {
Font->ta_Name = (STRPTR)"topaz.font";
FontX = FontY = Font->ta_YSize = 8;
}
DragKnobHeight = FontY;
if (DragKnobHeight < 12) DragKnobHeight = 12;
DragKnobWidth = (DragKnobHeight * 5) >> 2;
}
int CalcAllPos(struct Pro *Pr, struct Layout *Lay, WORD *ww, WORD *wh)
{
/* Calculate the position of all gadgets and put the final windowsize in ww and wh */
struct RastPort *rp = &Scr->RastPort, *myrp=NULL;
struct RFFTag *tag;
struct Space GLim; /* "rectangle" that gadgets are to be drawn within */
struct VisFldInfo *vf;
if (UserTextFont) {
/* Alloc and init a dummy RastPort for TextLength() with custom fonts */
if (!(myrp = AllocMem(sizeof(struct RastPort),0))) return MEM_ERR;
InitRastPort(myrp);
SetFont(myrp,UserTextFont);
rp = myrp;
}
Font = &Attr;
OffX = Scr->WBorLeft;
OffY = Scr->RastPort.TxHeight + Scr->WBorTop + 1;
/* Get the tabsize from the taglist */
if (tag = FindTag(&Lay->LayTags, TABSIZE))
TabSize = atoi(tag->Data);
else TabSize = DEFTABSIZE;
AdjustVars(rp);
CalcPos(Lay, &GLim, ww, wh, rp);
if (myrp) FreeMem(myrp, sizeof(struct RastPort));
if ((*ww>Scr->Width || *wh>Scr->Height) && UserTextFont) { /* Try screen font */
rp = &Scr->RastPort;
AdjustVars(rp);
CalcPos(Lay, &GLim, ww, wh, rp);
}
if (*ww > Scr->Width || *wh > Scr->Height) { /* Try Topaz 8 */
AdjustVars(NULL);
CalcPos(Lay, &GLim, ww, wh, NULL);
if (*ww > Scr->Width || *wh > Scr->Height) return WINSIZE_ERR;
}
/* Finally add GLim's offsets to all gadgets */
for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {
vf->Pos.XOffset += OffX + FontX + GLim.XOffset;
vf->Pos.YOffset += OffY + (FontY >> 1) + GLim.YOffset;
}
/* Window specifics */
DB_Zoom[0] = 0;
DB_Zoom[1] = OffY;
DB_Zoom[2] =
TextLength( &Scr->RastPort, (UBYTE *)Pr->Name, strlen((char *)Pr->Name))
+ TextLength( &Scr->RastPort, (UBYTE *)Lay->Name, strlen((char *)Lay->Name))
+ FontX + 80;
DB_Zoom[3] = Scr->WBorTop + Scr->RastPort.TxHeight + 1;
/* Make sure window is not too small */
if (*ww < (DB_Zoom[2] + 8 * FontX)) *ww = DB_Zoom[2] + 8 * FontX;
if (*wh < DragKnobHeight * 5) {
if (!Lay->FirstVisFldInfo) *wh = 10 * DragKnobHeight;
else *wh = 5 * DragKnobHeight;
}
return 0;
}
int CreateAllGadgets(struct Pro *Pr, struct Layout *Lay, WORD ww, WORD wh, char mode)
{
/* Create all gadgets with sizes, and positions fixed by CalcAllPos() */
struct FldInfo *f;
struct VisFldInfo *vf;
struct Gadget *g;
struct NewGadget ng;
struct RFFTag *tag;
struct RFFTag *sfmt; /* String format (left, right, center etc) */
LONG justification; /* String format (left, right, center etc) */
if (!(g = CreateContext(&Lay->GList))) return GAD_ERR;
ng.ng_TextAttr = Font;
ng.ng_VisualInfo = VisualInfo;
ng.ng_UserData = 0;
/* The drag gadget. (No dragbar in design mode) */
if (mode == USE_MODE) {
ng.ng_GadgetText = NULL;
ng.ng_GadgetID = SCROLLER_KIND; /* For our information, from gadtools.h */
ng.ng_Flags = 0;
if (MyArgArray[HORIZBAR]) {
ng.ng_LeftEdge = Scr->WBorLeft;
ng.ng_TopEdge = wh - Scr->WBorBottom - DragKnobHeight;
ng.ng_Width = ww - (Scr->WBorLeft + Scr->WBorRight);
ng.ng_Height = DragKnobHeight;
Lay->DragGad = g = CreateGadget(SCROLLER_KIND, g, &ng,
GTSC_Total, 1,
GTSC_Arrows, DragKnobWidth,
PGA_Freedom, LORIENT_HORIZ,
GA_Immediate, TRUE,
GA_RelVerify, TRUE,
TAG_DONE
);
}
else {
ng.ng_LeftEdge = ww - Scr->WBorRight - DragKnobWidth;
ng.ng_TopEdge = OffY;
ng.ng_Width = DragKnobWidth;
ng.ng_Height = wh - OffY - Scr->WBorBottom;
Lay->DragGad = g = CreateGadget(SCROLLER_KIND, g, &ng,
GTSC_Total, 1,
GTSC_Arrows, DragKnobHeight,
PGA_Freedom, LORIENT_VERT,
GA_Immediate, TRUE,
GA_RelVerify, TRUE,
TAG_DONE
);
}
} /* end-if RUN-MODE */
/* The other gadgets */
for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {
if (!(f = GetFldInfo(Pr, vf->Offset))) return RFF_ERR;
ng.ng_LeftEdge = vf->Pos.XOffset;
ng.ng_TopEdge = vf->Pos.YOffset;
ng.ng_Width = vf->Pos.Width;
ng.ng_Height = vf->Pos.Height;
ng.ng_GadgetText = vf->Name;
tag = SearchTag(CurrentPro, vf, NULL, PLACE);
if (tag && !Stricmp(tag->Data, "above")) /* Title is above gadget */
ng.ng_Flags = PLACETEXT_ABOVE;
else ng.ng_Flags = PLACETEXT_LEFT;
if (MyArgArray[HIGHLABEL]) ng.ng_Flags |= NG_HIGHLABEL;
tag = SearchTag(CurrentPro, vf, NULL, FTYP);
if (tag && !Stricmp(tag->Data, "checkbox"))
{
Lay->ComplexGadgets = TRUE; /* For UpdateGadgets() */
ng.ng_Width = (ng.ng_Height * 3) >> 1;
ng.ng_GadgetID = CHECKBOX_KIND; /* For our information, from gadtools.h */
vf->Gadget = g = CreateGadget(CHECKBOX_KIND, g, &ng,
GT_Underscore, '_',
GTCB_Scaled, TRUE,
TAG_DONE
);
}
else if (tag && !Stricmp(tag->Data, "cycle"))
{
Lay->ComplexGadgets = TRUE; /* For UpdateGadgets() */
ng.ng_GadgetID = CYCLE_KIND; /* For our information, from gadtools.h */
vf->Gadget = g = CreateGadget(CYCLE_KIND, g, &ng,
GT_Underscore, '_',
GTCY_Labels, vf->CEnt,
TAG_DONE
);
}
else if (tag && !Stricmp(tag->Data, "text"))
{
Lay->ComplexGadgets = TRUE; /* For UpdateGadgets() */
ng.ng_GadgetID = TEXT_KIND; /* For our information, from gadtools.h */
justification = GTJ_LEFT;
if (sfmt = SearchTag(CurrentPro, vf, NULL, SFMT)) {
if (!Stricmp(sfmt->Data, "right")) justification = GTJ_RIGHT;
else if (!Stricmp(sfmt->Data, "center")) justification = GTJ_CENTER;
}
vf->Gadget = g = CreateGadget(TEXT_KIND, g, &ng,
GTTX_Justification, justification,
GT_Underscore, '_',
GTTX_Clipped, TRUE,
GTTX_Border, TRUE,
GTTX_CopyText, TRUE,
TAG_DONE
);
}
else if (tag && !Stricmp(tag->Data, "textfield") && TextFieldClass) {
long bordertype = TEXTFIELD_BORDER_DOUBLEBEVEL;
vf->Label.FrontPen = MyArgArray[HIGHLABEL] ? Pens[HIGHLIGHTTEXTPEN] : Pens[TEXTPEN];
Lay->ComplexGadgets = TRUE; /* For UpdateGadgets() */
if (MyArgArray[NOBORDER]) bordertype = TEXTFIELD_BORDER_NONE;
justification = TEXTFIELD_ALIGN_LEFT;
if (sfmt = SearchTag(CurrentPro, vf, NULL, SFMT)) {
if (!Stricmp(sfmt->Data, "right")) justification = TEXTFIELD_ALIGN_RIGHT;
else if (!Stricmp(sfmt->Data, "center")) justification = TEXTFIELD_ALIGN_CENTER;
}
vf->Gadget = g = NewObject(TextFieldClass, NULL,
GA_ID, TEXTFIELD_KIND,
GA_Left, ng.ng_LeftEdge,
GA_Top, ng.ng_TopEdge,
GA_Width, ng.ng_Width,
GA_Height, ng.ng_Height,
GA_Previous, g,
GA_TabCycle, TRUE,
GA_IntuiText, &vf->Label,
TEXTFIELD_ClipStream, Iff0->iff_Stream,
TEXTFIELD_Border, bordertype,
TEXTFIELD_Alignment, justification,
TEXTFIELD_MaxSize, f->Len,
TEXTFIELD_TextAttr, (ULONG)Font,
TEXTFIELD_BlockCursor, TRUE,
TEXTFIELD_PassCommand, TRUE,
TAG_END);
vf->Gadget->Activation |= GACT_IMMEDIATE; /* To get gadgetdown events */
}
else { /* Assume string type as default */
ng.ng_GadgetID = STRING_KIND; /* For our information, from gadtools.h */
/* Handle string formatting */
justification = STRINGLEFT;
if (sfmt = SearchTag(CurrentPro, vf, NULL, SFMT)) {
if (!Stricmp(sfmt->Data, "right")) justification = STRINGRIGHT;
else if (!Stricmp(sfmt->Data, "center")) justification = STRINGCENTER;
}
vf->Gadget = g = CreateGadget(STRING_KIND, g, &ng,
STRINGA_ExitHelp, TRUE,
GTST_MaxChars, f->Len,
STRINGA_Justification, justification,
GT_Underscore, '_',
GTST_EditHook, &MyStrHook,
TAG_DONE
);
vf->Gadget->Activation |= GACT_IMMEDIATE; /* To get gadgetdown events */
} /* GA_Immediate tag is v39 */
}
if (Lay->FirstVisFldInfo) LastGad = Lay->FirstVisFldInfo->Gadget;
else LastGad = NULL;
return 0;
}
int AttachAllGadgets(struct Layout *Lay, WORD ww, WORD wh, char mode)
{
/* Attach all gadgets to an already opened window, and size the window accordingly */
/* Use DoOpenLayWindow() instead if window is closed */
struct IntuiMessage *m;
ULONG class;
WORD clearw, clearh; // Just so we don't clear more than neccesary.
clearw = (Lay->Window->Width < ww) ? Lay->Window->Width : ww;
clearh = (Lay->Window->Height < wh) ? Lay->Window->Height : wh;
/* Resize (and maybe move) window */
// Lay->Window->Flags |= WFLG_SIMPLE_REFRESH; /* Speed */
{
WORD x = (Lay->XPos >= 0) ? Lay->XPos : Lay->Window->LeftEdge;
WORD y = (Lay->YPos >= 0) ? Lay->YPos : Lay->Window->TopEdge;
ChangeWindowBox(Lay->Window, x, y, ww, wh);
}
/* The action is delayed until I get a IDCMP_NEWSIZE message. Ugly! */
for (;;) {
WaitPort(Lay->Window->UserPort);
while( m = GT_GetIMsg( Lay->Window->UserPort )) {
class = m->Class;
GT_ReplyIMsg(m);
if (class == IDCMP_NEWSIZE) goto SIZEOK;
}
}
SIZEOK:
// Lay->Window->Flags &= ~WFLG_SIMPLE_REFRESH; /* Speed */
if (mode == USE_MODE && MyArgArray[NOBORDER]) {
MyArgArray[NOSPEEDRENDER] = FALSE;
if (!SpeedRenderOn(Lay)) ByeBye();
}
AddGList(Lay->Window, Lay->GList, -1, -1, NULL);
/* Clear old gadget imagery */
EraseRect(Lay->Window->RPort, Lay->Window->BorderLeft, Lay->Window->BorderTop,
clearw - Lay->Window->BorderRight-1, clearh - Lay->Window->BorderBottom-1);
// RefreshWindowFrame(Lay->Window);
RefreshGList(Lay->GList, Lay->Window, NULL, -1);
GT_RefreshWindow( Lay->Window, NULL ); /* Must also be called. Works fine without however */
if (mode == DESIGN_MODE)
RemoveGList(Lay->Window, Lay->GList, -1);
else if (!MyArgArray[NOBORDER])
if (!SpeedRenderOn(Lay)) ByeBye();
return 0;
}
int DoOpenLayWindow(struct Pro *Pr, struct Layout *Lay, WORD ww, WORD wh)
{
/* Does the actual opening (in USE_MODE) */
WORD leftedge, topedge;
if (MyArgArray[NOBORDER]) {
MyArgArray[NOSPEEDRENDER] = FALSE;
if (!SpeedRenderOn(Lay)) ByeBye();
}
/* Position window nicely */
if (LastLeftEdge == -1) { /* No previous window to use */
leftedge = (Scr->Width - ww) >> 1; /* Middle */
topedge = (Scr->Height - wh) >> 1; /* Middle */
}
else {
leftedge = LastLeftEdge;
topedge = LastTopEdge;
}
if (Lay->XPos != -1) leftedge = Lay->XPos;
if (Lay->YPos != -1) topedge = Lay->YPos;
if ( ! ( Lay->Window = OpenWindowTags( NULL,
WA_Left, leftedge,
WA_Top, topedge,
WA_Width, ww,
WA_Height, wh,
WA_IDCMP, STRINGIDCMP|SCROLLERIDCMP|ARROWIDCMP|IDCMP_NEWSIZE|IDCMP_MENUPICK|IDCMP_CLOSEWINDOW|IDCMP_RAWKEY|IDCMP_VANILLAKEY|IDCMP_MENUHELP|IDCMP_REFRESHWINDOW,
WA_Flags, WFLG_NEWLOOKMENUS|WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET|WFLG_SMART_REFRESH|WFLG_ACTIVATE,
WA_Gadgets, Lay->GList,
WA_Title, Lay->Title,
WA_ScreenTitle, "db v" VERSION_NUMBER " ©1997-1998 David Ekholm, Marcin Orlowski",
WA_PubScreen, Scr,
WA_Zoom, DB_Zoom,
WA_MenuHelp, TRUE,
TAG_DONE )))
return WIN_ERR;
if (!Pr->Menu) OpenMenu(Pr);
SetMenuStrip(Lay->Window, Pr->Menu);
GT_RefreshWindow( Lay->Window, NULL);
/* AppWindow specifics */
Lay->AppWin = AddAppWindow(1, 1, Lay->Window, AWPort, NULL);
/* End of AppWindow specifics */
/* We delete the reference to the gadget borders to double the update speed */
/* We relink the information before windowclosing so that memory is freed */
if (!MyArgArray[NOBORDER])
if (!SpeedRenderOn(Lay)) ByeBye();
/* For IDCMP handling used in this file and in main() */
WinSig = 1L << Lay->Window->UserPort->mp_SigBit;
return 0;
}
int OpenLayWin(struct Pro *Pr, struct Layout *Lay)
{
/* Frontend function for the old db code */
int ret;
WORD ww, wh; /* Final window width and height */
if ((ret = CalcAllPos(Pr, Lay, &ww, &wh)) < 0) return ret;
if ((ret = CreateAllGadgets(Pr, Lay, ww, wh, USE_MODE)) < 0) return ret;
if ((ret = DoOpenLayWindow(Pr, Lay, ww, wh)) < 0) return ret;
return 0;
}